#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright 2014 Lukas Kemmer
#
# Licensed under the Apache License, Version 2.0 (the "License"); you
# may not use this file except in compliance with the License. You
# may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.

def replace(text, replacement_dict):
    for key in replacement_dict.keys():
        replacement = replacement_dict[key]
        if replacement.find('\n') != -1:
            pos = text.find(key)
            if pos != -1:
                indent = ' ' * pos
                replacement = ('\n' + indent).join(
                    [l for l in replacement.split('\n')])
        text = text.replace(key, replacement)

    if text.find('$') != -1:
        print(text)

    assert text.find("$") == -1
    return text


class Code:
    """For generating C++-code."""
    def __init__(self, indent=2, text=None):
        assert type(indent) is int
        self.indent_step = indent
        self.indent_level = 0
        if text is None:
            self._text = ""
        else:
            self._text = text

    def line(self, line):
        if line.strip().startswith('};') or line.strip().startswith('}'):
            self.indent_level -= 1

        self._text += self._indent() + line + '\n'

        if line.strip().endswith('{') and line.find('namespace') == -1:
            self.indent_level += 1

    def blank_line(self):
        self._text += '\n'

    def code(self, code):
        text = code.get_text()
        for line in text.split('\n'):
            self.line(line.strip())

    def append_raw(self, line):
        self._text += line

    def append_template(self, text_lines, replacement_dict):
        for line in text_lines:
            self.append_raw(self._indent() + replace(line, replacement_dict))

    def _include_guard(self, s):
        return '#ifndef %s\n#define %s\n\n' % (s, s)

    def _close_include_guard(self):
        self._text += '#endif\n'

    def _indent(self):
        return ' ' * self.indent_step * self.indent_level

    def get_text(self):
        return self._text

    def __str__(self):
        return self.get_text()

    def __iadd__(self, text):
        if isinstance(text, Code):
            self.code(text)
        else:
            self.line(text)
        return self

    def __add__(self, text):
        c2 = Code(indent=self.indent_step)
        c2._text = self.get_text() + "\n" + str(text)
        return c2

    def startswith(self, t):
        return self.get_text().startswith(t)


class Comment(Code):
    def __init__(self, text, indent=2):
        Code.__init__(self, indent)
        self.comment = text

    def get_text(self):
        return '// %s' % self.comment

class Include(Code):
    def __init__(self, include, indent=2):
        Code.__init__(self, indent)
        self.include = include

    def get_text(self):
        return '#include %s' % self.include

class IncludeGuard(Code):
    def __init__(self, include_guard, content=None, indent=2):
        Code.__init__(self, indent, text=content)
        self.include_guard = include_guard

    def get_text(self):
        return ('#ifndef %s\n#define %s\n%s\n#endif' %
                (self.include_guard, self.include_guard, Code.get_text(self)))

class Namespace(Code):
    def __init__(self, name, content=None, indent=2):
        Code.__init__(self, indent, content)
        self.name = name

    def get_text(self):
        return ('\nnamespace %s{\n\n%s} // namespace'
                % (self.name, Code.get_text(self)))


def _test():
    comment = Comment('Generated by fake_file.py')
    interface_cc = (comment +
                    Include('<string>') +
                    Include('"python/py-include.hh"') +
                    Include('"app/get-app-context.hh"') +
                    Include('"util/settings.hh"') +
                    Include('"util/setting-id.hh"'))
    print(interface_cc)


if __name__ == '__main__':
    _test()
